iT邦幫忙

2024 iThome 鐵人賽

DAY 15
0
佛心分享-SideProject30

用 Golang 實作 streamlit 系列 第 15

Day15 Typescript + React

  • 分享至 

  • xImage
  •  

根據前面的 component 的寫法, React 會是比較直接替代方案,並且順便加上 Typescript。

將 API 回傳的 Container Node 整理成:

export class Node {
  // component's prop
  props: any
  children: Node[]

  constructor(props: any) {
    this.props = props
    this.children = []
  }
}

並且準備好 API Body Type,和 Upload File Function Type:

export interface UpdateEvent {
  state_id?: string
  id?: string
  value?: any

  // 給 Button 用的【是否是暫時性的變動】
  is_temp?: boolean
}

就可以把 Component Typescript Function Parameter 寫成:

export interface Props {
  node: Node

  // component's callback
  // rerun api
  update: (event: UpdateEvent) => void
  
  // fileupload api
  upload: (file: File) => Promise<Response>
}

例如 Container DOM creator 可以改寫成:

export function TContainer({ node, update, upload }: Props) {
  return (
    <div id={node.props.id}>
      {
        node.children.map(child =>
          <TComponent node={child}
            update={update}
            upload={upload} />
        )
      }
    </div>
  )
}

對於原本的 Component Factory Function 也可以做以下更動:

  • Typing
  • 使用 Functor Dictionary 省去重複的 If-Then-Else
const creatorMap: { [id: string]: ((props: Props) => JSX.Element) } = {
  textbox_component: TTextbox,
  // ...
}

export function TComponent({ node, update, upload }: Props) {
  if (!(node.props.name in creatorMap)) {
    throw new Error(`unsupported component type: ${node.props.name}`);
  }

  return creatorMap[node.props.name]({ node, update, upload })
}

改成 React 最大的好處就是原本麻煩而且不是給人看的 DOM 操作 Code 可以寫成得很好看,
不過要注意到,有涉及 State 的地方,例如 Textbox ,之前為了避免戳 api 更新時把使用者輸入的資料洗掉,我們會把 component value 存在一個 global dictionary。

現在在使用 React ,我們要用到 react state 去保留 textbox value。


export function TTextbox(...) {
  const [value, setValue] = useState<string>(stateValues[node.props.id] || '')
  // ...
  return 
    // ...
    <input type="text"
      className="input"
      id={node.props.id}
      value={value}
      onChange={(event) => {
        stateValues[event.target.id] = event.target.value
        setValue(event.target.value)
      }}
      onBlur={(event) => {
        update({
          id: event.target.id,
          value: stateValues[event.target.id],
        })
      }}/>
    // ...
}

兩層 State 分別有不同的作用:

  • Global Dictionary → 在 api rerun 呼叫之間保留使用者輸入值
  • React State → React DOM 本身需要

上一篇
Day14 Component 實作告一段落
下一篇
Day16 Go Embed Build Assets
系列文
用 Golang 實作 streamlit 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言